# app/schedule_mgmt.py

from flask import Blueprint, request, jsonify, session, abort
from functools import wraps
from datetime import datetime, timedelta
from sqlalchemy import and_, or_
from . import db
from .models import Schedule

bp = Blueprint('schedule_mgmt', __name__, url_prefix='/api/schedules')


def login_required(f):
    @wraps(f)
    def wrapped(*args, **kwargs):
        if 'user_id' not in session:
            abort(401, description="未登录")
        return f(*args, **kwargs)

    return wrapped


@bp.before_request
@login_required
def ensure_login():
    # 所有接口均需登录
    pass


def parse_date(s):
    try:
        return datetime.strptime(s, '%Y-%m-%d').date()
    except Exception:
        abort(400, description="日期格式错误，应为 YYYY-MM-DD")


def parse_time(s):
    try:
        return datetime.strptime(s, '%H:%M').time()
    except Exception:
        abort(400, description="时间格式错误，应为 HH:MM")


def conflicts(user_id, date, start, end, exclude_ids=None):
    """检查指定日期时间段与其它排课是否冲突，排除 exclude_ids 列表。"""
    from sqlalchemy import and_, or_
    q = Schedule.query.filter_by(user_id=user_id, one_date=date)
    if exclude_ids:
        q = q.filter(~Schedule.id.in_(exclude_ids))
    clash = q.filter(
        or_(
            and_(Schedule.start_time <= start, Schedule.end_time > start),
            and_(Schedule.start_time < end,   Schedule.end_time >= end),
            and_(Schedule.start_time >= start, Schedule.end_time <= end)
        )
    ).first()
    return clash is not None


@bp.route('', methods=['GET'])
def list_schedules():
    """
    GET /api/schedules?date=YYYY-MM-DD
    返回指定日期所有排课列表
    """
    uid = session['user_id']
    date_str = request.args.get('date')
    if not date_str:
        return jsonify(error="缺少 date 参数"), 400
    try:
        date0 = datetime.strptime(date_str, '%Y-%m-%d').date()
    except ValueError:
        return jsonify(error="日期格式错误"), 400

    items = Schedule.query.filter_by(user_id=uid, one_date=date0).order_by(Schedule.start_time).all()
    result = []
    for s in items:
        result.append({
            "id": s.id,
            "student_name": s.student_name,
            "grade": s.grade,
            "status": s.status if hasattr(s, 'status') else "未上",  # 可扩展
            "start_time": s.start_time.strftime('%H:%M'),
            "end_time": s.end_time.strftime('%H:%M'),
            "course": s.course,
            "school": s.school
        })
    return jsonify(result), 200


@bp.route('/<int:sid>', methods=['GET'])
def get_schedule(sid):
    """
    GET /api/schedules/<sid>
    返回单条排课详情
    """
    uid = session['user_id']
    s = Schedule.query.filter_by(id=sid, user_id=uid).first_or_404()
    return jsonify({
        "id": s.id,
        "student_name": s.student_name,
        "course": s.course,
        "school": s.school,
        "grade": s.grade,
        "address": s.address,
        "fee": str(s.fee),
        "status": s.status,
        "date": s.one_date.strftime('%Y-%m-%d'),
        "start_time": s.start_time.strftime('%H:%M'),
        "end_time": s.end_time.strftime('%H:%M'),
        "remark": s.remark or ""
    }), 200


@bp.route('', methods=['POST'])
def create_schedule():
    data = request.get_json() or {}
    uid = session['user_id']

    # 1. 基本必填校验
    required = ['student_name', 'course', 'school', 'grade',
                'fee', 'type', 'start_time', 'end_time']
    for key in required:
        if not data.get(key):
            return jsonify(error=f"{key} 为必填项"), 400

    sched_type = data['type']
    start_time = parse_time(data['start_time'])
    end_time = parse_time(data['end_time'])
    if start_time >= end_time:
        return jsonify(error="结束时间必须晚于开始时间"), 400

    entries = []

    if sched_type == 'once':
        # 一次性排课
        if not data.get('one_date'):
            return jsonify(error="请选择排课日期"), 400
        date0 = parse_date(data['one_date'])

        # 冲突检测
        if conflicts(uid, date0, start_time, end_time):
            return jsonify(error=f"{date0} 时间段与已有排课冲突"), 400

        entries.append(Schedule(
            user_id=uid,
            student_name=data['student_name'],
            course=data['course'],
            school=data['school'],
            grade=data['grade'],
            address=data.get('address', ''),
            fee=data['fee'],
            type='once',
            one_date=date0,
            start_date=None,
            end_date=None,
            start_time=start_time,
            end_time=end_time,
            remark=data.get('remark', '')
        ))

    elif sched_type == 'weekly':
        # 每周排课
        for key in ['weekdays', 'start_date', 'end_date']:
            if not data.get(key):
                return jsonify(error="请选择星期及起止日期"), 400

        start_d = parse_date(data['start_date'])
        end_d = parse_date(data['end_date'])
        if start_d > end_d:
            return jsonify(error="结束日期必须不早于开始日期"), 400

        # 将星期名映射到 weekday() 值
        weekday_map = {"Mon": 0, "Tue": 1, "Wed": 2, "Thu": 3, "Fri": 4, "Sat": 5, "Sun": 6}
        desired = {weekday_map.get(d) for d in data['weekdays']}
        if None in desired:
            return jsonify(error="无效的星期值"), 400

        cur = start_d
        while cur <= end_d:
            if cur.weekday() in desired:
                # 冲突检测
                if conflicts(uid, cur, start_time, end_time):
                    return jsonify(error=f"{cur} 时间冲突"), 400

                entries.append(Schedule(
                    user_id=uid,
                    student_name=data['student_name'],
                    course=data['course'],
                    school=data['school'],
                    grade=data['grade'],
                    address=data.get('address', ''),
                    fee=data['fee'],
                    type='weekly',
                    one_date=cur,
                    start_date=start_d,
                    end_date=end_d,
                    start_time=start_time,
                    end_time=end_time,
                    remark=data.get('remark', '')
                ))
            cur += timedelta(days=1)

    else:
        return jsonify(error="无效的排课类型"), 400

    # 3. 批量插入
    db.session.bulk_save_objects(entries)
    db.session.commit()

    return jsonify(message="添加成功", count=len(entries)), 201


@bp.route('/<int:sid>/status', methods=['POST'])
def toggle_status(sid):
    """切换已上/未上"""
    sched = Schedule.query.filter_by(id=sid, user_id=session['user_id']).first_or_404()
    sched.status = '已上' if sched.status != '已上' else '未上'
    db.session.commit()
    return jsonify({"status": sched.status}), 200


@bp.route('/<int:sid>', methods=['DELETE'])
def delete_schedule(sid):
    """
    DELETE /api/schedules/<sid>
    仅删除 status='未上' 的本次排课
    """
    uid = session['user_id']
    s = Schedule.query.filter_by(id=sid, user_id=uid).first_or_404()
    if s.status != '未上':
        return jsonify(error="已完成排课无法删除"), 400
    db.session.delete(s)
    db.session.commit()
    return jsonify(message="删除本次成功"), 200


@bp.route('/<int:sid>/ongoing', methods=['DELETE'])
def delete_schedule_ongoing(sid):
    """
    DELETE /api/schedules/<sid>/ongoing
    从本次开始，删除同一“排课系列”中所有 status='未上' 的后续记录。
    """
    uid = session['user_id']
    first = Schedule.query.filter_by(id=sid, user_id=uid).first_or_404()
    if first.status != '未上':
        return jsonify(error="已完成排课无法删除"), 400

    # 构造“系列”过滤：同 user_id、相同学生/课程/学校/年级/学费、类型均为 weekly、
    # 且 one_date >= first.one_date，status='未上'
    deleted = db.session.query(Schedule).filter(
        Schedule.user_id == uid,
        Schedule.student_name == first.student_name,
        Schedule.course == first.course,
        Schedule.school == first.school,
        Schedule.grade == first.grade,
        Schedule.fee == first.fee,
        Schedule.type == first.type,
        Schedule.one_date >= first.one_date,
        Schedule.status == '未上'
    ).delete(synchronize_session=False)

    db.session.commit()
    return jsonify(message=f"删除本次及后续成功，共删除{deleted}条"), 200


@bp.route('/<int:sid>/modify', methods=['PUT'])
def modify_schedule(sid):
    uid  = session['user_id']
    orig = Schedule.query.filter_by(id=sid, user_id=uid).first_or_404()
    data = request.get_json() or {}
    sched_type = data.get('type')
    if sched_type not in ('once', 'weekly'):
        return jsonify(error="type 必须为 'once' 或 'weekly'"), 400

    if orig.status != '未上':
        return jsonify(error="已完成排课无法修改"), 400

    # 准备要在冲突检测中排除的原始记录 ID 列表
    exclude_ids = []
    if sched_type == 'once':
        exclude_ids = [sid]
    else:
        # 本次及后续系列：收集将被删除的所有记录 ID
        series = Schedule.query.filter(
            Schedule.user_id    == uid,
            Schedule.student_name == orig.student_name,
            Schedule.course     == orig.course,
            Schedule.school     == orig.school,
            Schedule.grade      == orig.grade,
            Schedule.fee        == orig.fee,
            Schedule.type       == orig.type,
            Schedule.one_date   >= orig.one_date,
            Schedule.status     == '未上'
        ).all()
        exclude_ids = [s.id for s in series]

    try:
        # 1) 冲突检测
        start_time = parse_time(data['start_time'])
        end_time   = parse_time(data['end_time'])
        if start_time >= end_time:
            raise ValueError("结束时间必须晚于开始时间")

        if sched_type == 'once':
            dt = parse_date(data['one_date'])
            if conflicts(uid, dt, start_time, end_time, exclude_ids):
                raise ValueError(f"{dt} 时间冲突")
        else:
            # weekly 类型
            start_d = parse_date(data['start_date'])
            end_d   = parse_date(data['end_date'])
            if start_d > end_d:
                raise ValueError("结束日期必须不早于开始日期")
            wdays = set(data.get('weekdays', []))
            weekday_map = {"Mon":0,"Tue":1,"Wed":2,"Thu":3,"Fri":4,"Sat":5,"Sun":6}
            cur = start_d
            while cur <= end_d:
                if cur.weekday() in {weekday_map[d] for d in wdays}:
                    if conflicts(uid, cur, start_time, end_time, exclude_ids):
                        raise ValueError(f"{cur} 时间冲突")
                cur += timedelta(days=1)

        # 2) 通过检测后，再在事务中删除旧记录并新增
        if sched_type == 'once':
            db.session.delete(orig)
        else:
            db.session.query(Schedule).filter(
                Schedule.user_id    == uid,
                Schedule.student_name == orig.student_name,
                Schedule.course     == orig.course,
                Schedule.school     == orig.school,
                Schedule.grade      == orig.grade,
                Schedule.fee        == orig.fee,
                Schedule.type       == orig.type,
                Schedule.one_date   >= orig.one_date,
                Schedule.status     == '未上'
            ).delete(synchronize_session=False)

        # 构造新增列表
        entries = []
        if sched_type == 'once':
            entries.append(Schedule(
                user_id      = uid,
                student_name = data['student_name'],
                course       = data['course'],
                school       = data['school'],
                grade        = data['grade'],
                address      = data.get('address',''),
                fee          = data['fee'],
                type         = 'once',
                one_date     = dt,
                start_time   = start_time,
                end_time     = end_time,
                remark       = data.get('remark','')
            ))
        else:
            # weekly：按天拆分
            cur = start_d
            while cur <= end_d:
                if cur.weekday() in {weekday_map[d] for d in wdays}:
                    entries.append(Schedule(
                        user_id      = uid,
                        student_name = data['student_name'],
                        course       = data['course'],
                        school       = data['school'],
                        grade        = data['grade'],
                        address      = data.get('address',''),
                        fee          = data['fee'],
                        type         = 'weekly',
                        one_date     = cur,
                        start_date   = start_d,
                        end_date     = end_d,
                        start_time   = start_time,
                        end_time     = end_time,
                        remark       = data.get('remark','')
                    ))
                cur += timedelta(days=1)

        db.session.bulk_save_objects(entries)
        db.session.commit()
        return jsonify(message="修改成功", count=len(entries)), 200

    except Exception as e:
        db.session.rollback()
        return jsonify(error=str(e)), 400
